package com.atguigu.tingshu.user.service.impl;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.IdUtil;
import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.rabbit.constant.MqConst;
import com.atguigu.tingshu.common.rabbit.service.RabbitService;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.model.user.UserInfo;
import com.atguigu.tingshu.model.user.UserPaidAlbum;
import com.atguigu.tingshu.model.user.UserPaidTrack;
import com.atguigu.tingshu.user.mapper.UserInfoMapper;
import com.atguigu.tingshu.user.mapper.UserPaidAlbumMapper;
import com.atguigu.tingshu.user.mapper.UserPaidTrackMapper;
import com.atguigu.tingshu.user.service.UserInfoService;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.j2objc.annotations.AutoreleasePool;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.text.CollationElementIterator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> implements UserInfoService {

    @Autowired
    private UserInfoMapper userInfoMapper;

    @Autowired
    private WxMaService wxMaService;

    @Autowired
    private RabbitService rabbitService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private UserPaidTrackMapper userPaidTrackMapper;

    @Autowired
    private UserPaidAlbumMapper userPaidAlbumMapper;


    /**
     * 小程序端提交临时凭据code，登录（调用微信接口获取微信账号唯一标识：openId）
     *
     * @param code 临时凭据
     * @return 对象，登录登录成功后：token
     */
    @Override
    public Map<String, String> wxLogin(String code) {

        try {
            // 1.根据入参提交临时票据，调用微信获取微信账户唯一标识接口，得到微信账户 openId
            WxMaJscode2SessionResult sessionInfo = wxMaService.getUserService().getSessionInfo(code);

            if (sessionInfo != null) {
                // 2.根据微信唯一标识查询用户记录
                String wxOpenId = sessionInfo.getOpenid();

                // 2.1 如果查询为空-将微信 OpenId 跟听书项目中用户关联 (新增用户记录中存储微信账户中的唯一标识)
                UserInfo userInfo = userInfoMapper.selectOne(new LambdaQueryWrapper<UserInfo>()
                        .eq(UserInfo::getWxOpenId, wxOpenId));

                if (null == userInfo) {
                    // 2.2 为首次登录用户构建用户对象，保存用户记录
                    userInfo = new UserInfo();
                    userInfo.setWxOpenId(wxOpenId);
                    userInfo.setNickname("听友" + IdUtil.getSnowflakeNextId());

                    userInfo.setAvatarUrl("https://oss.aliyuncs.com/aliyun_id_photo_bucket/default_handsome.jpg");
                    userInfo.setIsVip(0);
                    userInfoMapper.insert(userInfo);

                    // 2.3 初始化账户信息，发送rabbitmq异步消息，通知账户微服务新增账户记录
                    rabbitService.sendMessage(MqConst.EXCHANGE_USER, MqConst.ROUTING_USER_REGISTER, userInfo.getId().toString());
                }

                // 3. 基于用户记录生成 Token 将用户令牌存入 Redis Key: 前缀 + token
                // 											Value:用户信息 UserInfoVo
                String token = IdUtil.fastUUID();
                String loginKey = RedisConstant.USER_LOGIN_KEY_PREFIX + token;

                    // 排除用户隐私数据
                UserInfoVo userInfoVo = new UserInfoVo();
                BeanUtils.copyProperties(userInfo, userInfoVo);

                redisTemplate.opsForValue().set(loginKey,userInfoVo,RedisConstant.USER_LOGIN_KEY_TIMEOUT,TimeUnit.SECONDS);

                // 4.将用户token封装结果返回
                Map<String,String> mapResult = new HashMap<>();
                mapResult.put("token",token);
                return mapResult;
            }
            return null;
        } catch (Exception e) {
            log.error("[用户服务]微信登录异常：{}", e);
            throw new RuntimeException(e);
        }
    }


    /**
     * 获取登录用户信息
     * @param userId
     * @return
     */
    @Override
    public UserInfoVo getUserInfo(Long userId) {

        UserInfo userInfo = userInfoMapper.selectById(userId);

        UserInfoVo userInfoVo =  new UserInfoVo();

        BeanUtils.copyProperties(userInfo,userInfoVo);

        return userInfoVo;
    }
    /**
     * 更新用户信息
     * @param userId
     * @param userInfoVo
     */
    @Override
    public void updateUser(Long userId, UserInfoVo userInfoVo) {

        UserInfo userInfo = new UserInfo();
        userInfo.setId(userId);

        userInfo.setNickname(userInfoVo.getNickname());
        userInfo.setAvatarUrl(userInfoVo.getAvatarUrl());

        userInfoMapper.updateById(userInfo);

    }

    /**
     * 根据用户ID查询用户信息
     * @param userId
     * @return
     */
    @Override
    public UserInfoVo getUserInfoVoById(Long userId) {

        UserInfoVo userInfoVo = new UserInfoVo();

        UserInfo userInfo = userInfoMapper.selectById(userId);

        BeanUtils.copyProperties(userInfo,userInfoVo);

        return userInfoVo;
    }

    /**
     * 该接口提供给专辑服务，展示声音列表动态判断付费标识
     * 判断当前用户某一页中声音列表购买情况
     * @param userId
     * @param albumId
     * @param needChackTrackIdList 待检查购买情况当前专辑声音列表
     * @return data:{声音ID:购买结果} 结果:1(已购) 0(未购买)
     */
    @Override
    public Map<Long, Integer> userIsPaidTrack(Long userId, Long albumId, List<Long> needChackTrackIdList) {

        /*
         进入一个专辑详情页面，获取该专辑的声音列表
         查询登录的用户的购买信息，按顺序查询：
         1、是否购买了当前专辑
            a、购买了专辑，将当前专辑声音列表中的所有声音显示为“已购买”
            b、未购买当前专辑
         2、是否购买声音（查询 用户购买声音表 中是否包含当前 专辑声音ID）
            a、购买了声音
            b、未购买声音 将当前专辑待检查声音列表全部设为 “未购买” 状态
         */


        // 1.根据用户ID 和 专辑ID 获取 用户在该专辑已购声音数量
        Long count = userPaidAlbumMapper.selectCount(new LambdaQueryWrapper<UserPaidAlbum>()
                .eq(UserPaidAlbum::getUserId,userId)
                .eq(UserPaidAlbum::getAlbumId,albumId));
        // 根据专辑ID获取专辑对应的声音ID 集合，遍历声音集合,将集合中的对应 已购声音数量的value改为 1（已购）
        if (count > 0){
            Map<Long ,Integer> resultMap = new HashMap<>();
            for (Long trackId : needChackTrackIdList) {
                resultMap.put(trackId,1);
            }
            return resultMap;
        }

        // 2.在 用户已购声音表 中 查出和当前专辑声音ID相同的声音集合
        List<UserPaidTrack> userPaidTrackList =  userPaidTrackMapper.selectList(new LambdaQueryWrapper<UserPaidTrack>()
                .eq(UserPaidTrack::getUserId,userId)
                .in(UserPaidTrack::getTrackId,needChackTrackIdList));


        // 2.1 不存在声音购买记录-将待检查声音列表购买状态设置为：0
        if (CollectionUtil.isEmpty(userPaidTrackList)){
            Map<Long,Integer> resultMap = new HashMap<>();
            for (UserPaidTrack userPaidTrack : userPaidTrackList) {
                resultMap.put(userPaidTrack.getTrackId(),0);
            }
            return resultMap;
        }

        // 2.2 存在声音购买记录 循环判断待检查声音ID找出哪些是已购，哪些是未购买
        List<Long> userPaidTrackIdList = userPaidTrackList.stream().map(UserPaidTrack::getTrackId).collect(Collectors.toList());

        Map<Long,Integer> resultMap = new HashMap<>();

        for (Long needChackTrackId : needChackTrackIdList) {
            if (userPaidTrackIdList.contains(needChackTrackId)){
                resultMap.put(needChackTrackId,1);
            } else {
                resultMap.put(needChackTrackId,0);
            }
        }

        return resultMap;
    }


}
